# pythonProject5/api/v1/routes/ws_realtime.py
# 仅处理 WebSocket 实时翻译
from fastapi import APIRouter, WebSocket, Query
from sqlalchemy.orm import Session
import json
import logging
import os
import asyncio
import tempfile
from datetime import datetime
from pathlib import Path

from starlette.websockets import WebSocketDisconnect, WebSocketState

from core.asr_engine import asr_engine
from core.translation_engine import translation_engine
from db.session import SessionLocal  # 手动创建 session
from models.db import TranslationRecord
from api.v1.auth import get_current_user_ws  # 必须支持手动传 db
from core.utils.audio import AudioStreamProcessor, validate_audio_chunk, create_temp_audio_file, cleanup_temp_files
from core.utils.websocket_utils import check_websocket_state, safe_send_json, safe_close_websocket

router = APIRouter(tags=["Real-time"])

TEMP_DIR = "temp_ws"
os.makedirs(TEMP_DIR, exist_ok=True)
logger = logging.getLogger(__name__)

@router.websocket("/ws/realtime_translate")
async def websocket_realtime_translate(
    websocket: WebSocket,
    token: str = Query(...)  # 通过 URL 传 token
):
    """
    WebSocket 实时语音识别 + 流式翻译
    URL: ws://host/v1/ws/realtime_translate?token=xxx
    初始化消息: {
        "source_lang": "zh", 
        "target_lang": "en", 
        "chunk_duration": 2.0,      # 音频块时长（秒），建议2-3秒
        "enable_streaming": true     # 是否启用流式翻译
    }
    音频数据: binary
    停止命令: text "stop"
    返回格式:
    - 实时翻译: {"type": "streaming", "source_text": "源文本片段", "translated_text": "翻译片段"}
    - 最终结果: {"status": "success", "source_text": "完整源文本", "translated_text": "完整翻译文本", "record_id": 123}
    """
    temp_audio_path = None
    audio_file = None
    user_id = None
    username = None
    db: Session = None
    chunk_duration = 2.0  # 默认2秒一个音频块
    enable_streaming = True  # 默认启用流式翻译

    # 创建音频流处理器
    audio_processor = AudioStreamProcessor(chunk_duration=chunk_duration)
    
    # 用于累积完整音频的临时文件
    full_audio_path = None
    full_audio_file = None
    
    # 标记是否已经保存过记录，避免重复保存
    record_saved = False
    
    try:
        # 1. 手动创建数据库会话
        db = SessionLocal()

        # 2. 接受连接 - 在认证前先接受连接，让客户端知道连接已建立
        await websocket.accept()
        logger.info("WebSocket连接已接受，开始认证")
        
        # 3. 认证（传入 db）
        try:
            user = await get_current_user_ws(token, db)
            user_id = user["id"]
            username = user["username"]
            logger.info(f"用户认证成功: {username} (ID: {user_id})")
        except Exception as auth_e:
            # 认证失败，发送错误消息后关闭连接
            error_msg = f"认证失败: {str(auth_e)}"
            logger.error(error_msg)
            await safe_send_json(websocket, {"status": "error", "message": error_msg})
            await safe_close_websocket(websocket, code=4001, reason="认证失败")
            return
        
        # 等待一小段时间确保连接完全建立
        await asyncio.sleep(0.1)
        
        # 发送连接确认消息
        if not await safe_send_json(websocket, {"status": "connected", "user": username}):
            logger.error("发送连接确认消息失败")
            return

        # 4. 接收初始化配置
        try:
            init_text = await websocket.receive_text()
            init = json.loads(init_text)
            source_lang = init.get("source_lang", "auto")
            target_lang = init.get("target_lang", "en")
            chunk_duration = init.get("chunk_duration", 2.0)
            enable_streaming = init.get("enable_streaming", True)
            
            # 更新音频处理器的块时长
            audio_processor.chunk_duration = chunk_duration
            
            await safe_send_json(websocket, {
                "status": "initialized", 
                "config": {
                    "source_lang": source_lang,
                    "target_lang": target_lang,
                    "chunk_duration": chunk_duration,
                    "enable_streaming": enable_streaming
                }
            })
        except Exception as e:
            await safe_send_json(websocket, {"status": "error", "message": "初始化失败，请发送正确的JSON配置"})
            await safe_close_websocket(websocket, code=1003, reason="初始化失败")
            return

        # 5. 创建临时音频文件（用于保存完整的音频）
        full_audio_path = os.path.join(TEMP_DIR, f"stream_{user_id}_{int(datetime.utcnow().timestamp())}.webm")
        full_audio_file = open(full_audio_path, "wb")

        # 6. 开始接收音频流
        logger.info("开始接收音频流...")
        while True:
            try:
                # 添加超时机制，防止长时间阻塞
                data = await asyncio.wait_for(websocket.receive(), timeout=30.0)
                logger.debug(f"收到数据类型: {list(data.keys())}")
                
                if "bytes" in data:
                    audio_data = data["bytes"]
                    audio_data_size = len(audio_data)
                    
                    # 将音频数据写入完整音频文件
                    if full_audio_file and not full_audio_file.closed:
                        full_audio_file.write(audio_data)
                        logger.debug(f"写入完整音频数据: {audio_data_size} bytes")
                    
                    # 如果启用流式翻译，添加到音频处理器
                    if enable_streaming:
                        # 添加音频数据到处理器
                        should_process = audio_processor.add_audio_data(audio_data)
                        
                        if should_process:
                            # 获取音频块并处理
                            audio_chunk = audio_processor.get_audio_chunk()
                            if audio_chunk and len(audio_chunk) > 2048:  # 确保音频块足够大
                                try:
                                    # 创建临时音频块文件
                                    temp_audio_path = create_temp_audio_file(audio_chunk, user_id, "chunk")
                                    
                                    # 检查路径是否有效
                                    if not temp_audio_path or not os.path.exists(temp_audio_path) or os.path.getsize(temp_audio_path) < 1024:
                                        logger.debug(f"跳过处理 - 临时音频文件无效或太小: {temp_audio_path}")
                                        continue
                                    
                                    # 处理这个音频块（流式识别+翻译）
                                    await process_streaming_chunk(
                                        websocket=websocket,
                                        audio_path=temp_audio_path,
                                        source_lang=source_lang,
                                        target_lang=target_lang
                                    )
                                except Exception as e:
                                    logger.error(f"处理音频块失败: {e}")
                                finally:
                                    # 处理完成后删除临时文件
                                    if temp_audio_path and os.path.exists(temp_audio_path):
                                        os.remove(temp_audio_path)
                                        temp_audio_path = None
                    
                elif "text" in data:
                    text_message = data["text"].strip().lower()
                    logger.info(f"收到文本消息: {text_message}")
                    if text_message == "stop":
                        logger.info("收到停止命令")
                        
                        # 处理剩余的音频数据 - 但不保存到数据库（避免重复）
                        if enable_streaming:
                            remaining_chunk = audio_processor.flush_buffer()
                            if remaining_chunk and len(remaining_chunk) > 2048:  # 增加最小大小限制
                                try:
                                    temp_audio_path = create_temp_audio_file(remaining_chunk, user_id, "final_chunk")
                                    
                                    # 检查路径是否有效
                                    if not temp_audio_path or not os.path.exists(temp_audio_path) or os.path.getsize(temp_audio_path) < 1024:
                                        logger.debug(f"跳过处理最终块 - 临时音频文件无效或太小: {temp_audio_path}")
                                        continue
                                    
                                    # 只做流式处理，不保存记录
                                    await process_streaming_chunk(
                                        websocket=websocket,
                                        audio_path=temp_audio_path,
                                        source_lang=source_lang,
                                        target_lang=target_lang
                                    )
                                except Exception as e:
                                    logger.warning(f"处理最终音频块失败 (可以忽略): {e}")
                                finally:
                                    if temp_audio_path and os.path.exists(temp_audio_path):
                                        os.remove(temp_audio_path)
                                        temp_audio_path = None
                        
                        break
                    elif text_message == "ping":
                        # 响应心跳
                        logger.debug("响应心跳")
                        await safe_send_json(websocket, {"type": "pong"})
                        
            except asyncio.TimeoutError:
                # 发送心跳检查连接
                logger.debug("发送心跳检查连接")
                if not await safe_send_json(websocket, {"type": "heartbeat"}):
                    logger.warning("心跳发送失败，连接可能已断开")
                    break
            except WebSocketDisconnect:
                logger.info("客户端主动断开连接")
                break
            except Exception as e:
                logger.error(f"接收数据失败: {e}")
                break

        # 7. 关闭完整音频文件
        if full_audio_file:
            full_audio_file.close()
            logger.info(f"完整音频文件已关闭: {full_audio_path}")

        # 8. 处理完整音频 - 生成最终结果
        logger.info("音频接收完成，处理完整音频...")
        
        # 在处理前检查连接状态
        if not check_websocket_state(websocket):
            logger.warning("WebSocket连接已断开，跳过完整音频处理")
            return
        
        if full_audio_path and os.path.exists(full_audio_path):
            file_size = os.path.getsize(full_audio_path)
            logger.info(f"开始处理完整音频文件: {full_audio_path}, 大小: {file_size} bytes")
            
            if file_size > 0:
                # ASR
                if not asr_engine.is_ready():
                    logger.error("ASR引擎未就绪")
                    await safe_send_json(websocket, {"status": "error", "message": "ASR引擎未就绪，请稍后重试"})
                    return
                    
                logger.info("开始完整ASR识别...")
                asr_result = asr_engine.transcribe(full_audio_path, language=source_lang)
                source_text = asr_result.get("text", "").strip()
                duration = asr_result.get("duration", 0)
                logger.info(f"完整ASR识别结果: '{source_text}', 时长: {duration}s")

                if not source_text:
                    logger.warning("ASR未识别出文本")
                    await safe_send_json(websocket, {"status": "error", "message": "未识别出文本"})
                    return

                # 翻译完整文本
                try:
                    logger.info(f"开始翻译完整文本: {source_lang} -> {target_lang}")
                    # 对于 RealTranslationEngine，使用新的 translate_audio 方法
                    if hasattr(translation_engine, 'translate_audio'):
                        logger.info("使用 translate_audio 方法")
                        trans_result = translation_engine.translate_audio(
                            audio_path=full_audio_path,
                            source_lang=source_lang,
                            target_lang=target_lang,
                            enable_translation=True,
                            return_segments=False
                        )
                        translated_text = trans_result.get("translated_text", "")
                    else:
                        logger.info("使用 translate 方法")
                        # 对于 MockTranslationEngine，使用 translate 方法
                        trans_result = translation_engine.translate(source_text, source_lang=source_lang, target_lang=target_lang)
                        translated_text = trans_result.get("translated_text", "")
                    
                    logger.info(f"完整翻译结果: '{translated_text}'")
                except Exception as e:
                    logger.error(f"翻译失败: {e}", exc_info=True)
                    translated_text = source_text  # 翻译失败时使用原文

                # 只有当源文本有实际内容且不为空，并且还没有保存过记录时才保存
                if source_text and source_text.strip() and not record_saved:
                    logger.info("保存翻译记录到数据库...")
                    record = TranslationRecord(
                        user_id=user_id,
                        source_audio_path=full_audio_path,
                        source_text=source_text,
                        target_text=translated_text,
                        source_language=source_lang,
                        target_language=target_lang,
                        duration_seconds=duration
                    )
                    db.add(record)
                    db.commit()
                    db.refresh(record)
                    record_saved = True  # 标记已保存记录
                    logger.info(f"记录已保存，ID: {record.id}")

                    # 返回最终结果
                    logger.info("准备发送最终翻译结果...")
                    
                    # 在发送前再次检查连接状态
                    if not check_websocket_state(websocket):
                        logger.warning("WebSocket连接已断开，无法发送最终翻译结果")
                        return
                    
                    result_data = {
                        "status": "success",
                        "type": "final",
                        "source_text": source_text,
                        "translated_text": translated_text,
                        "record_id": record.id,
                        "duration": duration
                    }
                    logger.info(f"发送最终翻译结果: {result_data}")
                    
                    await safe_send_json(websocket, result_data)
                elif record_saved:
                    logger.info("记录已经保存过，跳过重复保存")
                    await safe_send_json(websocket, {
                        "status": "success", 
                        "type": "final",
                        "message": "处理完成（记录已保存）"
                    })
                else:
                    logger.warning("源文本为空，不保存记录")
                    await safe_send_json(websocket, {
                        "status": "success", 
                        "type": "final",
                        "message": "未识别出有效文本，未保存记录"
                    })
            else:
                logger.warning(f"完整音频文件为空: {full_audio_path}, 大小: {file_size} bytes")
                await safe_send_json(websocket, {"status": "error", "message": "未收到有效音频"})
        else:
            logger.warning("未找到完整音频文件")
            await safe_send_json(websocket, {"status": "error", "message": "未收到有效音频"})

    except WebSocketDisconnect:
        logger.info(f"WebSocket 断开 (用户: {username or user_id})")
    except Exception as e:
        logger.error(f"WebSocket 错误: {e}", exc_info=True)
        # 只有在连接仍然正常时才尝试发送错误消息
        if check_websocket_state(websocket):
            try:
                await safe_send_json(websocket, {"status": "error", "message": "服务器内部错误"})
            except Exception as send_error:
                logger.warning(f"发送错误消息失败: {send_error}")
    finally:
        # 清理资源（避免在已断开的连接上操作）
        logger.info(f"开始清理WebSocket资源 (用户: {username or user_id})")
        
        # 关闭数据库连接
        if db:
            try:
                db.close()
                logger.debug("数据库连接已关闭")
            except Exception as db_error:
                logger.warning(f"关闭数据库连接失败: {db_error}")
        
        # 关闭音频文件
        if full_audio_file and not full_audio_file.closed:
            try:
                full_audio_file.close()
                logger.debug("完整音频文件已关闭")
            except Exception as file_error:
                logger.warning(f"关闭完整音频文件失败: {file_error}")
        
        # 删除临时文件
        temp_files = []
        if temp_audio_path and os.path.exists(temp_audio_path):
            temp_files.append(temp_audio_path)
        if full_audio_path and os.path.exists(full_audio_path):
            temp_files.append(full_audio_path)
            
        cleanup_temp_files(temp_files)
                
        # 确保WebSocket连接正确关闭（仅在连接存在时）- 放在最后进行
        try:
            if check_websocket_state(websocket):
                # 添加短暂延迟，确保所有消息都已发送
                await asyncio.sleep(0.5)
                await safe_close_websocket(websocket, code=1000, reason="服务端正常关闭")
        except Exception as ws_close_error:
            logger.warning(f"WebSocket关闭失败: {ws_close_error}")


@router.websocket("/ws/voice_input")
async def websocket_voice_input(
    websocket: WebSocket,
    token: str = Query(...)  # 通过 URL 传 token
):
    """
    WebSocket 实时语音输入 + 实时翻译
    URL: ws://host/v1/ws/voice_input?token=xxx
    
    初始化消息: {
        "source_lang": "zh", 
        "target_lang": "en",
        "chunk_duration": 3.0,  // 音频块时长（秒）
        "enable_realtime": true  // 是否启用实时返回
    }
    
    音频数据: binary chunks
    停止命令: text "stop"
    
    返回格式:
    - 实时识别: {"type": "partial", "text": "部分识别的文本"}
    - 最终结果: {"type": "final", "source_text": "...", "translated_text": "..."}
    - 错误: {"type": "error", "message": "错误信息"}
    """
    temp_audio_path = None
    audio_file = None
    user_id = None
    username = None
    db: Session = None
    chunk_duration = 3.0  # 默认3秒一个音频块
    enable_realtime = True
    source_lang = "auto"
    target_lang = "en"
    
    # 音频流处理器
    audio_processor = AudioStreamProcessor(chunk_duration=chunk_duration)
    
    try:
        # 1. 手动创建数据库会话
        db = SessionLocal()

        # 2. 接受连接 - 在认证前先接受连接，让客户端知道连接已建立
        await websocket.accept()
        logger.info("WebSocket语音输入连接已接受，开始认证")
        
        # 3. 认证（传入 db）
        try:
            user = await get_current_user_ws(token, db)
            user_id = user["id"]
            username = user["username"]
            logger.info(f"语音输入用户认证成功: {username} (ID: {user_id})")
        except Exception as auth_e:
            # 认证失败，发送错误消息后关闭连接
            error_msg = f"认证失败: {str(auth_e)}"
            logger.error(error_msg)
            await safe_send_json(websocket, {"type": "error", "message": error_msg})
            await safe_close_websocket(websocket, code=4001, reason="认证失败")
            return
        
        await safe_send_json(websocket, {
            "type": "connected", 
            "user": username,
            "message": "语音输入WebSocket已连接"
        })

        # 4. 接收初始化配置
        try:
            init_text = await websocket.receive_text()
            init = json.loads(init_text)
            source_lang = init.get("source_lang", "auto")
            target_lang = init.get("target_lang", "en")
            chunk_duration = init.get("chunk_duration", 3.0)
            enable_realtime = init.get("enable_realtime", True)
            
            await safe_send_json(websocket, {
                "type": "config", 
                "source_lang": source_lang,
                "target_lang": target_lang,
                "chunk_duration": chunk_duration,
                "enable_realtime": enable_realtime
            })
        except Exception as e:
            await safe_send_json(websocket, {
                "type": "error", 
                "message": "初始化失败，请发送正确的JSON配置"
            })
            await safe_close_websocket(websocket, code=1003, reason="初始化失败")
            return

        # 5. 开始接收音频流
        while True:
            try:
                # 添加超时机制，防止长时间阻塞
                data = await asyncio.wait_for(websocket.receive(), timeout=30.0)
                
                if "bytes" in data:
                    # 接收音频数据
                    audio_data = data["bytes"]
                    
                    # 验证音频数据
                    is_valid, error_msg = validate_audio_chunk(audio_data)
                    if not is_valid:
                        await safe_send_json(websocket, {
                            "type": "error",
                            "message": f"无效的音频数据: {error_msg}"
                        })
                        continue
                    
                    # 添加到处理器
                    should_process = audio_processor.add_audio_data(audio_data)
                    
                    if should_process:
                        # 获取音频块并处理 - 不是最终处理，不保存记录
                        audio_chunk = audio_processor.get_audio_chunk()
                        if audio_chunk:
                            await process_audio_chunk(
                                websocket, audio_chunk, user_id, source_lang, 
                                target_lang, enable_realtime, db, is_final=False
                            )
                            
                elif "text" in data:
                    text_message = data["text"].strip().lower()
                    if text_message == "stop":
                        logger.info("收到停止命令，处理剩余音频数据")
                        # 处理剩余的音频数据 - 设置为最终处理，允许保存记录
                        remaining_chunk = audio_processor.flush_buffer()
                        if remaining_chunk:
                            await process_audio_chunk(
                                websocket, remaining_chunk, user_id, source_lang, 
                                target_lang, enable_realtime, db, is_final=True
                            )
                        break
                    elif text_message == "flush":
                        logger.info("收到刷新命令，立即处理当前缓冲区")
                        # 立即处理当前缓冲区 - 不是最终处理，不保存记录
                        current_chunk = audio_processor.flush_buffer()
                        if current_chunk:
                            await process_audio_chunk(
                                websocket, current_chunk, user_id, source_lang, 
                                target_lang, enable_realtime, db, is_final=False
                            )
                    elif text_message == "ping":
                        # 响应心跳
                        await safe_send_json(websocket, {"type": "pong"})
                        
            except asyncio.TimeoutError:
                # 发送心跳检查连接
                if not await safe_send_json(websocket, {"type": "heartbeat"}):
                    logger.warning("心跳发送失败，连接可能已断开")
                    break
            except WebSocketDisconnect:
                logger.info(f"WebSocket 断开 (用户: {username or user_id})")
                break
            except Exception as e:
                logger.error(f"接收数据失败: {e}")
                await safe_send_json(websocket, {
                    "type": "error",
                    "message": "数据接收失败"
                })
                break

    except WebSocketDisconnect:
        logger.info(f"WebSocket 断开 (用户: {username or user_id})")
    except Exception as e:
        logger.error(f"WebSocket 错误: {e}", exc_info=True)
        # 只有在连接仍然正常时才尝试发送错误消息
        if check_websocket_state(websocket):
            try:
                await safe_send_json(websocket, {
                    "type": "error", 
                    "message": "服务器内部错误"
                })
            except Exception as send_error:
                logger.warning(f"发送错误消息失败: {send_error}")
    finally:
        # 清理资源
        logger.info(f"开始清理语音输入WebSocket资源 (用户: {username or user_id})")
        
        # 关闭数据库连接
        if db:
            try:
                db.close()
                logger.debug("数据库连接已关闭")
            except Exception as db_error:
                logger.warning(f"关闭数据库连接失败: {db_error}")
        
        # 删除临时文件
        if temp_audio_path and os.path.exists(temp_audio_path):
            try:
                os.remove(temp_audio_path)
                logger.debug(f"临时文件已删除: {temp_audio_path}")
            except Exception as e:
                logger.warning(f"无法删除临时文件: {e}")
                
        # 确保WebSocket连接正确关闭（仅在连接存在时）- 放在最后进行
        try:
            if check_websocket_state(websocket):
                # 添加短暂延迟，确保所有消息都已发送
                await asyncio.sleep(0.5)
                await safe_close_websocket(websocket, code=1000, reason="服务端正常关闭")
        except Exception as ws_close_error:
            logger.warning(f"WebSocket关闭失败: {ws_close_error}")


async def process_streaming_chunk(
    websocket: WebSocket,
    audio_path: str,
    source_lang: str = "auto",
    target_lang: str = "en"
) -> None:
    """
    处理音频块并返回流式识别/翻译结果
    """
    try:
        # 1. 检查文件
        if not os.path.exists(audio_path):
            logger.error(f"流式处理：音频文件不存在: {audio_path}")
            return
            
        file_size = os.path.getsize(audio_path)
        if file_size < 1024:  # 增加最小文件大小要求到1KB
            logger.debug(f"流式处理：音频文件太小: {file_size} bytes")
            return
            
        # 2. 尝试验证音频文件格式
        try:
            # 获取文件扩展名
            file_ext = os.path.splitext(audio_path)[1].lower()
            
            # 检查音频格式
            if file_ext == '.webm':
                # 简单验证WebM文件头
                with open(audio_path, "rb") as f:
                    header = f.read(4)
                    if header != b'\x1a\x45\xdf\xa3':  # WebM文件头标识
                        logger.warning(f"流式处理：可能不是有效的WebM文件 ({audio_path})")
            elif file_ext == '.wav':
                # WAV文件检查
                logger.info(f"流式处理：使用WAV格式音频 ({audio_path})")
            else:
                logger.info(f"流式处理：使用未知格式音频 ({audio_path}), 扩展名: {file_ext}")
        except Exception as ve:
            logger.warning(f"流式处理：验证音频文件失败: {ve}")
            
        # 3. ASR 识别
        if not asr_engine.is_ready():
            logger.error("流式处理：ASR引擎未就绪")
            await safe_send_json(websocket, {
                "type": "error",
                "message": "ASR引擎未就绪，请稍后重试"
            })
            return
            
        try:
            logger.debug(f"流式处理：开始识别音频块: {audio_path}")
            asr_result = asr_engine.transcribe(
                Path(audio_path), 
                language=source_lang,
                return_segments=False
            )
            
            source_text = asr_result.get("text", "").strip()
            if not source_text:
                logger.debug("流式处理：未识别出文本")
                return
        except Exception as asr_err:
            logger.error(f"流式处理：ASR处理失败: {asr_err}")
            return  # 识别失败，直接返回
        
        # 4. 翻译
        logger.debug(f"流式处理：开始翻译: '{source_text}'")
        try:
            # 使用翻译引擎
            if hasattr(translation_engine, 'translate_audio'):
                # 使用音频翻译
                try:
                    trans_result = translation_engine.translate_audio(
                        audio_path=audio_path,
                        source_lang=source_lang,
                        target_lang=target_lang,
                        enable_translation=True,
                        return_segments=False
                    )
                    translated_text = trans_result.get("translated_text", "")
                except Exception as audio_trans_err:
                    # 如果音频翻译失败，回退到文本翻译
                    logger.warning(f"流式处理：音频翻译失败，回退到文本翻译: {audio_trans_err}")
                    trans_result = translation_engine.translate(
                        source_text, 
                        source_lang=source_lang, 
                        target_lang=target_lang
                    )
                    translated_text = trans_result.get("translated_text", "")
            else:
                # 使用文本翻译
                trans_result = translation_engine.translate(
                    source_text, 
                    source_lang=source_lang, 
                    target_lang=target_lang
                )
                translated_text = trans_result.get("translated_text", "")
        except Exception as e:
            logger.error(f"流式处理：翻译失败: {e}")
            translated_text = source_text  # 翻译失败时使用原文
        
        # 5. 发送流式结果
        logger.info(f"流式处理：发送部分结果: '{source_text}' -> '{translated_text}'")
        await safe_send_json(websocket, {
            "type": "streaming",
            "source_text": source_text,
            "translated_text": translated_text,
            "timestamp": datetime.now().isoformat()
        })
        
    except Exception as e:
        logger.error(f"流式处理音频块失败: {e}", exc_info=True)
        try:
            await safe_send_json(websocket, {
                "type": "error",
                "message": f"音频块处理失败: {str(e)}"
            })
        except Exception as send_error:
            logger.warning(f"发送错误消息失败: {send_error}")


async def process_audio_chunk(
    websocket: WebSocket,
    audio_data: bytes,
    user_id: int,
    source_lang: str,
    target_lang: str,
    enable_realtime: bool,
    db: Session,
    is_final: bool = False
):
    """
    处理音频块并返回识别/翻译结果
    """
    temp_audio_path = None
    
    try:
        # 1. 创建临时音频文件
        temp_audio_path = create_temp_audio_file(audio_data, user_id, "chunk")
        
        # 2. 检查文件大小（过滤太小的音频）
        if os.path.getsize(temp_audio_path) < 1024:  # 小于1KB
            return
        
        # 3. ASR 识别
        if not asr_engine.is_ready():
            logger.error("ASR引擎未就绪")
            await safe_send_json(websocket, {
                "type": "error",
                "message": "ASR引擎未就绪，请稍后重试"
            })
            return
            
        asr_result = asr_engine.transcribe(
            Path(temp_audio_path), 
            language=source_lang,
            return_segments=False
        )
        
        source_text = asr_result.get("text", "").strip()
        if not source_text:
            return
        
        # 4. 翻译
        try:
            # 对于 RealTranslationEngine，使用新的 translate_audio 方法
            if hasattr(translation_engine, 'translate_audio'):
                # 创建临时音频文件用于翻译
                temp_translate_path = create_temp_audio_file(audio_data, user_id, "translate")
                trans_result = translation_engine.translate_audio(
                    audio_path=temp_translate_path,
                    source_lang=source_lang,
                    target_lang=target_lang,
                    enable_translation=True,
                    return_segments=False
                )
                translated_text = trans_result.get("translated_text", "")
                # 清理临时翻译文件
                if os.path.exists(temp_translate_path):
                    os.remove(temp_translate_path)
            else:
                # 对于 MockTranslationEngine，使用 translate 方法
                trans_result = translation_engine.translate(
                    source_text, 
                    source_lang=source_lang, 
                    target_lang=target_lang
                )
                translated_text = trans_result.get("translated_text", "")
        except Exception as e:
            logger.error(f"翻译失败: {e}")
            translated_text = source_text  # 翻译失败时使用原文
        
        # 5. 发送结果
        if is_final:
            # 最终结果，只有当源文本有效且这是真正的最终处理时才保存到数据库
            if source_text and source_text.strip():
                record = TranslationRecord(
                    user_id=user_id,
                    source_audio_path=temp_audio_path,
                    source_text=source_text,
                    target_text=translated_text,
                    source_language=source_lang,
                    target_language=target_lang,
                    duration_seconds=asr_result.get("duration", 0)
                )
                db.add(record)
                db.commit()
                db.refresh(record)
                
                await safe_send_json(websocket, {
                    "type": "final",
                    "source_text": source_text,
                    "translated_text": translated_text,
                    "record_id": record.id,
                    "duration": asr_result.get("duration", 0),
                    "timestamp": datetime.now().isoformat()
                })
            else:
                # 如果没有有效文本，发送无记录的最终结果
                await safe_send_json(websocket, {
                    "type": "final",
                    "message": "未识别出有效文本，未保存记录",
                    "timestamp": datetime.now().isoformat()
                })
        else:
            # 实时结果 - 不保存到数据库，只发送临时结果
            if enable_realtime and source_text and source_text.strip():
                await safe_send_json(websocket, {
                    "type": "partial",
                    "source_text": source_text,
                    "translated_text": translated_text,
                    "timestamp": datetime.now().isoformat()
                })
        
    except Exception as e:
        logger.error(f"处理音频块失败: {e}", exc_info=True)
        logger.error(f"音频文件路径: {temp_audio_path}")
        logger.error(f"音频数据大小: {len(audio_data)} bytes")
        try:
            await safe_send_json(websocket, {
                "type": "error",
                "message": f"音频处理失败: {str(e)}"
            })
        except Exception as send_error:
            logger.warning(f"发送错误消息失败: {send_error}")
    finally:
        # 清理临时文件
        if temp_audio_path and os.path.exists(temp_audio_path):
            try:
                os.remove(temp_audio_path)
            except Exception as e:
                logger.warning(f"无法删除临时文件: {e}")